/**
 * DVN: Distributed Virtual Network Simulation Platform
 * Copyright (c) 2006-2009 Tyson Malchow <tyson.malchow@gmail.com>
 *
 * This file is part of the DVN distributed virtual network simulation
 * program.
 *
 * DVN is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * DVN is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with DVN.  If not, see <http://www.gnu.org/licenses/>.
 */
#include <sys/time.h>
#include <stdlib.h>
#include "simop.h"
#include "evtracker.h"

simop_list_tp simop_list_create (void) {
	return evtracker_create(10, 1);
}


void simop_list_destroy( simop_list_tp list ) {
	simop_tp sop;
	while((sop=evtracker_get_nextevent(list, NULL, 1))){
		free(sop);
	}
	evtracker_destroy(list);
}

void simop_list_add( simop_list_tp list, simop_tp op, ptime_t time) {
	evtracker_insert_event(list, time, op);
}

int simop_list_size( simop_list_tp list ) {
	return evtracker_get_numevents(list);
}

simop_tp simop_get_next( simop_list_tp list, ptime_t * time ) {
	return evtracker_get_nextevent(list, time, 1);
}

simop_tp simop_look_next( simop_list_tp list, ptime_t * time) {
	return evtracker_get_nextevent(list, time, 0);
}

simop_tp simop_nbdf_decode(nbdf_tp nb) {
	nbdf_tp inner;
	simop_tp sop = malloc(sizeof(*sop));

	nbdf_read(nb, "itn", &sop->opcode, &sop->target_time, &inner);

	switch(sop->opcode) {
		case SIMOP_CODE_CNODES:
			nbdf_read(inner, "tiiiiciiis",
					&sop->target_time,
					&sop->detail.cnodes.quantity,

					&sop->detail.cnodes.network_id,
					&sop->detail.cnodes.module_id,

					&sop->detail.cnodes.logging_level,
					&sop->detail.cnodes.logging_channel,

					&sop->detail.cnodes.flags,

					&sop->detail.cnodes.tracker_id,
					&sop->detail.cnodes.bootstrap_id,
 
                                        sizeof(sop->detail.cnodes.cl_args),
                                        sop->detail.cnodes.cl_args
					);
			break;

		case SIMOP_CODE_NETWORK:
			nbdf_read(inner, "tiiiiiic",
					&sop->target_time,
					&sop->detail.network.id1,
					&sop->detail.network.id2,

					&sop->detail.network.base_delay,
					&sop->detail.network.width,
					&sop->detail.network.tail_width,
					&sop->detail.network.reliability,

					&sop->detail.network.method
					);
			break;

		case SIMOP_CODE_END:
			nbdf_read(inner, "t", &sop->target_time);
			break;

		case SIMOP_CODE_MODLOAD:
			nbdf_read(inner, "tis",
					&sop->target_time,
					&sop->detail.modload.id,
					sizeof(sop->detail.modload.file),
					sop->detail.modload.file);
			break;
	}

	nbdf_free(inner);

	return sop;
}

nbdf_tp simop_nbdf_encode(simop_tp sop) {
	nbdf_tp nb = NULL;
	nbdf_tp nb_outer = NULL;

	if(!sop)
		return NULL;

	switch(sop->opcode) {
		case SIMOP_CODE_CNODES:
			nb = nbdf_construct("tiiiiciiis",
					sop->target_time,
					sop->detail.cnodes.quantity,

					sop->detail.cnodes.network_id,
					sop->detail.cnodes.module_id,

					sop->detail.cnodes.logging_level,
					sop->detail.cnodes.logging_channel,

					sop->detail.cnodes.flags,

					sop->detail.cnodes.tracker_id,
					sop->detail.cnodes.bootstrap_id,

					sop->detail.cnodes.cl_args
					);
			break;

		case SIMOP_CODE_NETWORK:
			nb = nbdf_construct("tiiiiiic",
					sop->target_time,
					sop->detail.network.id1,
					sop->detail.network.id2,

					sop->detail.network.base_delay,
					sop->detail.network.width,
					sop->detail.network.tail_width,
					sop->detail.network.reliability,

					sop->detail.network.method
					);
			break;

		case SIMOP_CODE_END:
			nb = nbdf_construct("t",
					sop->target_time);
			break;

		case SIMOP_CODE_MODLOAD:
			nb = nbdf_construct("tis",
					sop->target_time,
					sop->detail.modload.id,
					sop->detail.modload.file);
			break;
	}

	nb_outer = nbdf_construct("itn", sop->opcode, sop->target_time, nb);
	nbdf_free(nb);

	return nb_outer;
}
